import socket
from json import dumps, loads
from random import randint, random
from socket import AF_INET, SOCK_DGRAM, socket, timeout
from time import sleep
def printf(type: str, *args):
	print(type, *args)
port1 = 10000
port2 = 10001
timeouts = 3
# 创建一个TCP/IP套接字
bits = 2  # 2个bit，即4种状态
serial_numbers = 2 ** bits
window_size = 2 ** bits - 1  # 窗口大小
def get_items(n):
	array = []
	result = []
	for i in range(0, serial_numbers):
		array.append(i)
	for i in range(n, n + window_size):
		result.append(array[i % len(array)])
	return result
def delay():
	return random() * 0.1
def sort_and_filter(array: list[dict], window_base: int):
	unique_acks = set()  # 用集合存储已经出现过的 ACK 值
	result = []
	for item in array:
		ack = item['ACK']
		if ack not in unique_acks:
			unique_acks.add(ack)
			result.append(item)
	final_result = []
	for j in range(0, window_size):
		flag=True
		for i in result:
			if i["ACK"] == (window_base + j) % serial_numbers:
				final_result.append(i)
				flag=False
		if flag:
			break
	return final_result
def receive(type: str, port: int, file_name: str):
	global address, ACK
	ACK = -1
	sock = socket(AF_INET, SOCK_DGRAM)
	window_base = 0
	receive_datas = []
	# 绑定套接字到一个地址和端口号
	server_address = ('localhost', port)
	printf(type, 'starting up on %s port %s' % server_address)
	sock.bind(server_address)  # 监听传入的连接
	while True:
		sleep(random())
		if not randint(0, 3):  # 模拟迟到的数据包
			continue
		data, address = sock.recvfrom(4096)
		if not data:
			break
		data_json = loads(data.decode())
		temp_ACK = data_json["ACK"]
		if temp_ACK == window_base:
			receive_data = data_json["data"]
			if receive_data == "\0":
				break
			receive_datas.append(receive_data)
			printf(type, 'received %s bytes from %s: %s, ACK is %d' % (len(receive_data), address, receive_data, temp_ACK))  # 打印接收到的消息
			window_base = (window_base + 1) % serial_numbers
			ACK = temp_ACK
		else:
			printf(type, 'ACK is wrong', data_json)
		# 发送确认消息给客户端
		if randint(0, 3):
			confirm = dumps({"ACK": ACK})
			sock.sendto(confirm.encode(), address)  # 发送确认消息给客户端
			printf(type, f'sent: {confirm}')
		else:
			printf(type, f'confirmation {ACK} not sent')
	with open(file_name, 'w') as f:
		f.write(''.join(receive_datas))
# 等待下一个数据包的到来
def send(type: str, port: int, send_data: list[str]):
	window_base = 0
	sock = socket(AF_INET, SOCK_DGRAM)
	# 连接到服务器地址和端口号
	server_address = ('localhost', port)
	try:
		current = 0
		while True:
			sleep(random())  # 模拟网络延迟
			# 发送数据给服务器
			if current >= len(send_data):
				break
			messages = []
			for i in range(0, window_size):
				cur = current + i
				if cur >= len(send_data):
					break
				data_to_send = send_data[cur]
				message = dumps({"data": data_to_send, "ACK": (window_base + i) % serial_numbers})
				if randint(0, 3):
					sock.sendto(message.encode(), server_address)
					messages.append(message)
				if data_to_send == "\0":
					break
				i += 1
			printf(type, 'messages sent:', messages)
			# -----------------------下面是接收确认消息-----------------------
			sock.settimeout(timeouts)
			while True:
				sleep(random())
				if not randint(0, 3):  # 模拟迟到的数据包
					continue
				try:
					data, server = sock.recvfrom(16)
				except timeout:
					printf(type, 'timeout occurred')
					break
				except Exception:
					continue
				if not randint(0, 3):  # 模拟丢包
					break
				if data:
					data_decode = loads(data.decode())
					ACK = data_decode["ACK"]
					get_item = get_items(window_base)
					if ACK in get_item:
						printf(type, 'received confirmation:', data_decode)
						window_base = (ACK + 1) % serial_numbers
						current += get_item.index(ACK) + 1
					else:
						printf(type, 'ACK is wrong', ACK)
				break
	# 等待下一个数据包的到来
	finally:
		# 关闭连接
		sock.close()